/*
 *
 * Copyright (C) 2012 Walter Lütgenau
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * 
 *      http://www.apache.org/licenses/LICENSE-2.0
 * 
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 * 
 */
package offset.nodes.client.chooser.view;

import java.awt.Rectangle;
import java.awt.event.ActionEvent;
import java.awt.event.KeyEvent;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.util.ResourceBundle;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.jcr.RepositoryException;
import javax.swing.AbstractAction;
import javax.swing.JComponent;
import javax.swing.KeyStroke;
import javax.swing.ListSelectionModel;
import javax.swing.event.ListSelectionEvent;
import javax.swing.event.ListSelectionListener;
import javax.swing.table.AbstractTableModel;
import offset.nodes.client.model.ActivePanelContainer;
import offset.nodes.client.model.NodeTypes;
import offset.nodes.client.model.SimpleNamespaceRegistry;
import offset.nodes.client.virtual.model.jcr.QName;
import offset.nodes.client.virtual.model.jcr.nodetype.NodeTypeDefinition;

/**
 *
 * @author Walter Lütgenau
 */
public class TypeChooserPanel extends javax.swing.JPanel {

    NodeTypes types;
    NodeTypeDefinition[] definitions = new NodeTypeDefinition[0];
    static ResourceBundle bundle = ResourceBundle.getBundle("offset/nodes/client/view/resources/ClientBundle"); // NOI18N
    ActivePanelContainer container = null;
    private static final KeyStroke ENTER_KEY = KeyStroke.getKeyStroke(KeyEvent.VK_ENTER, 0);
    static final String ENTER_ACTION = "EnterDefaultButton";

    /** Creates new form TypeChooserPanel */
    public TypeChooserPanel(NodeTypes types) {
        initComponents();
        this.types = types;
        init(null);
    }

    public TypeChooserPanel(NodeTypes types, QName uriFilter) {
        initComponents();
        this.types = types;
        init(uriFilter);
    }

    public void setContainer(ActivePanelContainer container) {
        this.container = container;
    }

    public String getSelectedType() {
        if (typesTable.getSelectedRowCount() == 1)
            return SimpleNamespaceRegistry.getInstance().toPrefixName(definitions[typesTable.getSelectedRow()].getName());

        return null;
    }

    public void setSelectedType(String type) {
        int newSelected = -1;

        for (int i = 0; i < definitions.length; i++) {
            if (SimpleNamespaceRegistry.getInstance().toPrefixName(definitions[i].getName()).equals(type)) {
                newSelected = i;
                break;
            }
        }

        if (newSelected < 0)
            return;

        typesTable.getSelectionModel().setSelectionInterval(newSelected, newSelected);
        Rectangle rect = typesTable.getCellRect(newSelected, TypeDefinitionsTableModel.COLUMN_LOCALNAME, true);
        typesTable.scrollRectToVisible(rect);

        if (container != null)
            container.enableOkButton(true);
    }

    public NodeTypeDefinition getSelectedDefinition() {
        if (typesTable.getSelectedRowCount() == 1)
            return definitions[typesTable.getSelectedRow()];

        return null;
    }

    public void initFocus() {
        typesTable.requestFocusInWindow();
    }

    class DoubleClickAdapter extends MouseAdapter {

        @Override
        public void mousePressed(MouseEvent e) {
            if (container != null && e.getClickCount() == 2 && !typesTable.isEditing())
                container.executeOk();
        }
    }

    public static final int COLUMN_NAMESPACE_MAX_WIDTH = 120;

    protected void init(QName uriFilter) {
        try {
            for (String prefix : SimpleNamespaceRegistry.getInstance().getPrefixes()) {
                namespaceCombo.addItem(prefix);
            }

            typesTable.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
            typesTable.getInputMap(JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT).put(ENTER_KEY, ENTER_ACTION);
            typesTable.getActionMap().put(ENTER_ACTION, new AbstractAction() {

                @Override
                public void actionPerformed(ActionEvent e) {
                    if (container != null)
                        container.executeOk();
                }
            });
            typesTable.requestFocusInWindow();
            typesTable.getColumnModel().getColumn(TypeDefinitionsTableModel.COLUMN_NAMESPACE).setMaxWidth(COLUMN_NAMESPACE_MAX_WIDTH);
            typesTable.addMouseListener(new DoubleClickAdapter());
            typesTable.getSelectionModel().addListSelectionListener(new ListSelectionListener() {

                @Override
                public void valueChanged(ListSelectionEvent e) {
                    if (container != null)
                        container.enableOkButton(true);
                }
            });

            if (uriFilter != null) {
                definitions = types.getArray(uriFilter);
                namespaceCombo.setSelectedItem(SimpleNamespaceRegistry.getInstance().getPrefix(uriFilter.getNamespaceURI()));
            } else
                definitions = types.getArray();
            ((TypeDefinitionsTableModel) typesTable.getModel()).refresh();
        } catch (RepositoryException ex) {
            Logger.getLogger(TypeChooserPanel.class.getName()).log(Level.SEVERE, null, ex);
        }
    }

    class TypeDefinitionsTableModel extends AbstractTableModel {

        public static final int COLUMN_LOCALNAME = 0;
        public static final int COLUMN_NAMESPACE = 1;

        public void refresh() {
            fireTableDataChanged();
        }

        public String getColumnName(int col) {
            switch (col) {
                case COLUMN_LOCALNAME:
                    return bundle.getString("typeChooser.localName");

                case COLUMN_NAMESPACE:
                    return bundle.getString("typeChooser.nameSpace");

                default:
                    return "";
            }
        }

        @Override
        public int getColumnCount() {
            return 2;
        }

        @Override
        public int getRowCount() {
            return definitions.length;
        }

        @Override
        public Object getValueAt(int rowIndex, int columnIndex) {
            switch (columnIndex) {
                case COLUMN_LOCALNAME:
                    return definitions[rowIndex].getName().getLocalName();

                case COLUMN_NAMESPACE:
                    return SimpleNamespaceRegistry.getInstance().getPrefix(definitions[rowIndex].getName().getNamespaceURI());

                default:
                    return "";
            }
        }
    }

    /** This method is called from within the constructor to
     * initialize the form.
     * WARNING: Do NOT modify this code. The content of this method is
     * always regenerated by the Form Editor.
     */
    @SuppressWarnings("unchecked")
    // <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
    private void initComponents() {

        namespaceLabel = new javax.swing.JLabel();
        namespaceCombo = new javax.swing.JComboBox();
        typesLabel = new javax.swing.JLabel();
        typesScrollbar = new javax.swing.JScrollPane();
        typesTable = new javax.swing.JTable();

        java.util.ResourceBundle bundle = java.util.ResourceBundle.getBundle("offset/nodes/client/view/resources/ClientBundle"); // NOI18N
        namespaceLabel.setText(bundle.getString("typeChooser.namespaces")); // NOI18N

        namespaceCombo.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                selectNamespace(evt);
            }
        });

        typesLabel.setText(bundle.getString("typeChooser.types")); // NOI18N

        typesTable.setAutoCreateRowSorter(true);
        typesTable.setModel(new TypeDefinitionsTableModel());
        typesTable.addKeyListener(new java.awt.event.KeyAdapter() {
            public void keyTyped(java.awt.event.KeyEvent evt) {
                selectTypeByKeyboard(evt);
            }
        });
        typesScrollbar.setViewportView(typesTable);

        javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this);
        this.setLayout(layout);
        layout.setHorizontalGroup(
            layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(layout.createSequentialGroup()
                .addGap(29, 29, 29)
                .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                    .addGroup(layout.createSequentialGroup()
                        .addComponent(typesLabel)
                        .addContainerGap(383, Short.MAX_VALUE))
                    .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup()
                        .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING)
                            .addComponent(typesScrollbar, javax.swing.GroupLayout.Alignment.LEADING, javax.swing.GroupLayout.DEFAULT_SIZE, 375, Short.MAX_VALUE)
                            .addGroup(layout.createSequentialGroup()
                                .addComponent(namespaceLabel)
                                .addGap(28, 28, 28)
                                .addComponent(namespaceCombo, 0, 288, Short.MAX_VALUE)))
                        .addGap(41, 41, 41))))
        );
        layout.setVerticalGroup(
            layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(layout.createSequentialGroup()
                .addGap(19, 19, 19)
                .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
                    .addComponent(namespaceCombo, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
                    .addComponent(namespaceLabel))
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
                .addComponent(typesLabel)
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                .addComponent(typesScrollbar, javax.swing.GroupLayout.DEFAULT_SIZE, 172, Short.MAX_VALUE)
                .addGap(20, 20, 20))
        );
    }// </editor-fold>//GEN-END:initComponents

    private void selectNamespace(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_selectNamespace
        Object[] namespaces = namespaceCombo.getSelectedObjects();
        if (namespaces.length == 1 && ((String) namespaces[0]).length() == 0)
            definitions = types.getArray();
        else {
            QName[] namespaceQNames = new QName[namespaces.length];

            for (int i = 0; i < namespaces.length; i++) {
                namespaceQNames[i] = new QName(SimpleNamespaceRegistry.getInstance().getURI((String) namespaces[i]), "");
            }

            definitions = types.getArray(namespaceQNames);
        }
        ((TypeDefinitionsTableModel) typesTable.getModel()).refresh();
        typesTable.requestFocusInWindow();
    }//GEN-LAST:event_selectNamespace

    private void selectTypeByKeyboard(java.awt.event.KeyEvent evt) {//GEN-FIRST:event_selectTypeByKeyboard
        int selected = typesTable.getSelectedRow();
        if (selected < 0)
            selected = 0;

        int newSelected = -1;
        for (int i = selected + 1; i < definitions.length; i++) {
            if (Character.toLowerCase(definitions[i].getName().getLocalName().charAt(0)) == Character.toLowerCase(evt.getKeyChar())) {
                newSelected = i;
                break;
            }
        }

        if (newSelected < 0)
            for (int i = 0; i < selected; i++) {
                if (Character.toLowerCase(definitions[i].getName().getLocalName().charAt(0)) == Character.toLowerCase(evt.getKeyChar())) {
                    newSelected = i;
                    break;
                }
            }

        if (newSelected >= 0) {
            typesTable.getSelectionModel().setSelectionInterval(newSelected, newSelected);
            Rectangle rect = typesTable.getCellRect(newSelected, TypeDefinitionsTableModel.COLUMN_LOCALNAME, true);
            typesTable.scrollRectToVisible(rect);
        }

    }//GEN-LAST:event_selectTypeByKeyboard
    // Variables declaration - do not modify//GEN-BEGIN:variables
    private javax.swing.JComboBox namespaceCombo;
    private javax.swing.JLabel namespaceLabel;
    private javax.swing.JLabel typesLabel;
    private javax.swing.JScrollPane typesScrollbar;
    private javax.swing.JTable typesTable;
    // End of variables declaration//GEN-END:variables
}
